#include "stdafx.h"
#include "FileFindW.h"

CFileFindW::CFileFindW(void)
{
	m_pFoundInfo = NULL;
	m_hContext = NULL;
	m_pNextInfo = NULL;
}

CFileFindW::~CFileFindW(void)
{
	Close();
}

void CFileFindW::Close()
{
	if (m_pFoundInfo != NULL)
	{
		delete m_pFoundInfo;
		m_pFoundInfo = NULL;
	}

	if (m_pNextInfo != NULL)
	{
		delete m_pNextInfo;
		m_pNextInfo = NULL;
	}

	if (m_hContext != NULL)
	{
		if (m_hContext != INVALID_HANDLE_VALUE)
			CloseContext();
		m_hContext = NULL;
	}
}

void CFileFindW::CloseContext()
{
	::FindClose(m_hContext);
}

BOOL CFileFindW::FindFile(LPCTSTR pstrName)
{
	if (pstrName == NULL)
		pstrName = _T("*.*");
	else if (lstrlen(pstrName) >= (_countof(((WIN32_FIND_DATAW*) m_pNextInfo)->cFileName)))
	{
		::SetLastError(ERROR_BAD_ARGUMENTS);
		return FALSE;		
	}
	
	m_pNextInfo = new WIN32_FIND_DATAW;

	WIN32_FIND_DATAW *pFindData = (WIN32_FIND_DATAW *)m_pNextInfo;

	CString cTmp = pstrName;
	Checked::wcscpy_s (pFindData->cFileName, _countof(pFindData->cFileName), CT2CW((LPCTSTR)cTmp));

	cTmp.Format("\\\\?\\%s", pstrName);
	m_hContext = FindFirstFileW(CT2CW((LPCTSTR)cTmp), m_pNextInfo);
	if (m_hContext == INVALID_HANDLE_VALUE)
	{
		DWORD dwTemp = ::GetLastError();
		Close();
		::SetLastError(dwTemp);
		return FALSE;
	}

	LPTSTR pstrRoot = m_strRoot.GetBufferSetLength(_MAX_PATH);
	LPCTSTR pstr = _tfullpath(pstrRoot, pstrName, _MAX_PATH);

	// passed name isn't a valid path but was found by the API
	ASSERT(pstr != NULL);
	if (pstr == NULL)
	{
		m_strRoot.ReleaseBuffer(0);
		Close();
		::SetLastError(ERROR_INVALID_NAME);
		return FALSE;
	}
	else
	{
		TCHAR strDrive[_MAX_DRIVE], strDir[_MAX_DIR];
		Checked::tsplitpath_s(pstrRoot, strDrive, _MAX_DRIVE, strDir, _MAX_DIR, NULL, 0, NULL, 0);
		Checked::tmakepath_s(pstrRoot, _MAX_PATH, strDrive, strDir, NULL, NULL);
		m_strRoot.ReleaseBuffer(-1);
	}
	return TRUE;
}

BOOL CFileFindW::FindNextFile()
{
	if (m_hContext == NULL)
		return FALSE;
	if (m_pFoundInfo == NULL)
		m_pFoundInfo = new WIN32_FIND_DATAW;

	void* pTemp = m_pFoundInfo;
	m_pFoundInfo = m_pNextInfo;
	m_pNextInfo = (LPWIN32_FIND_DATAW)pTemp;
	return ::FindNextFileW(m_hContext, m_pFoundInfo);
}

BOOL CFileFindW::MatchesMask(DWORD dwMask)
{
	if (m_pFoundInfo != NULL)
		return (!!(((LPWIN32_FIND_DATAW) m_pFoundInfo)->dwFileAttributes & dwMask));
	else
		return FALSE;
}

BOOL CFileFindW::IsDots()
{
	// return TRUE if the file name is "." or ".." and
	// the file is a directory

	BOOL bResult = FALSE;
	if (m_pFoundInfo != NULL && IsDirectory())
	{
		LPWIN32_FIND_DATA pFindData = (LPWIN32_FIND_DATA) m_pFoundInfo;
		if (pFindData->cFileName[0] == '.')
		{
			if (pFindData->cFileName[1] == '\0' ||
				(pFindData->cFileName[1] == '.' &&
				 pFindData->cFileName[2] == '\0'))
			{
				bResult = TRUE;
			}
		}
	}

	return bResult;
}

CString CFileFindW::GetFileURL() 
{
	CString strResult("file://");
	strResult += GetFilePath();
	return strResult;
}

CString CFileFindW::GetRoot() 
{
	return m_strRoot;
}

CString CFileFindW::GetFilePath() 
{
	CString strResult = m_strRoot;
	LPCTSTR pszResult;
	LPCTSTR pchLast;
	pszResult = strResult;
	pchLast = _tcsdec( pszResult, pszResult+strResult.GetLength() );
    ENSURE(pchLast!=NULL);
	if ((*pchLast != _T('\\')) && (*pchLast != _T('/')))
		strResult += m_chDirSeparator;
	strResult += GetFileName();
	return strResult;
}

CString CFileFindW::GetFileTitle() 
{
	CString strFullName = GetFileName();
	CString strResult;

	Checked::tsplitpath_s(strFullName, NULL, 0, NULL, 0, 
		strResult.GetBuffer(_MAX_FNAME), _MAX_FNAME, NULL, 0);

	strResult.ReleaseBuffer();
	return strResult;
}

CString CFileFindW::GetFileName() 
{
	CString ret;

	if (m_pFoundInfo != NULL)
		ret = m_pFoundInfo->cFileName;
	return ret;
}

ULONGLONG CFileFindW::GetLength() 
{
	ULARGE_INTEGER nFileSize;

	if (m_pFoundInfo != NULL)
   {
	  nFileSize.LowPart = ((LPWIN32_FIND_DATA) m_pFoundInfo)->nFileSizeLow;
	  nFileSize.HighPart = ((LPWIN32_FIND_DATA) m_pFoundInfo)->nFileSizeHigh;
   }
   else
   {
	  nFileSize.QuadPart = 0;
   }

   return nFileSize.QuadPart;
}

BOOL CFileFindW::GetLastAccessTime(FILETIME* pTimeStamp)
{
	if (m_pFoundInfo != NULL && pTimeStamp != NULL)
	{
		*pTimeStamp = ((LPWIN32_FIND_DATA) m_pFoundInfo)->ftLastAccessTime;
		return TRUE;
	}
	else
		return FALSE;
}

BOOL CFileFindW::GetLastWriteTime(FILETIME* pTimeStamp)
{
	if (m_pFoundInfo != NULL && pTimeStamp != NULL)
	{
		*pTimeStamp = ((LPWIN32_FIND_DATA) m_pFoundInfo)->ftLastWriteTime;
		return TRUE;
	}
	else
		return FALSE;
}

BOOL CFileFindW::GetCreationTime(FILETIME* pTimeStamp)
{
	if (m_pFoundInfo != NULL && pTimeStamp != NULL)
	{
		*pTimeStamp = ((LPWIN32_FIND_DATA) m_pFoundInfo)->ftCreationTime;
		return TRUE;
	}
	else
		return FALSE;
}

BOOL CFileFindW::GetLastAccessTime(CTime& refTime)
{
	if (m_pFoundInfo != NULL)
	{
		if (CTime::IsValidFILETIME(((LPWIN32_FIND_DATA) m_pFoundInfo)->ftLastAccessTime))
		{
			refTime = CTime(((LPWIN32_FIND_DATA) m_pFoundInfo)->ftLastAccessTime);
		}
		else
		{
			refTime = CTime();
		}
		return TRUE;
	}
	else
		return FALSE;
}

BOOL CFileFindW::GetLastWriteTime(CTime& refTime)
{
	if (m_pFoundInfo != NULL)
	{
		if (CTime::IsValidFILETIME(((LPWIN32_FIND_DATA) m_pFoundInfo)->ftLastWriteTime))
		{
			refTime = CTime(((LPWIN32_FIND_DATA) m_pFoundInfo)->ftLastWriteTime);
		}
		else
		{
			refTime = CTime();
		}
		return TRUE;
	}
	else
		return FALSE;
}

BOOL CFileFindW::GetCreationTime(CTime& refTime)
{
	if (m_pFoundInfo != NULL)
	{
		if (CTime::IsValidFILETIME(((LPWIN32_FIND_DATA) m_pFoundInfo)->ftCreationTime))
		{
			refTime = CTime(((LPWIN32_FIND_DATA) m_pFoundInfo)->ftCreationTime);
		}
		else
		{
			refTime = CTime();
		}
		return TRUE;
	}
	else
		return FALSE;
}

BOOL CFileFindW::IsReadOnly()
{
	return MatchesMask(FILE_ATTRIBUTE_READONLY); 
}

BOOL CFileFindW::IsDirectory()
{	
	return MatchesMask(FILE_ATTRIBUTE_DIRECTORY); 
}

BOOL CFileFindW::IsCompressed()
{
	return MatchesMask(FILE_ATTRIBUTE_COMPRESSED); 
}

BOOL CFileFindW::IsSystem()
{
	return MatchesMask(FILE_ATTRIBUTE_SYSTEM); 
}

BOOL CFileFindW::IsHidden()
{
	return MatchesMask(FILE_ATTRIBUTE_HIDDEN); 
}

BOOL CFileFindW::IsTemporary()
{
	return MatchesMask(FILE_ATTRIBUTE_TEMPORARY); 
}

BOOL CFileFindW::IsNormal()
{
	return MatchesMask(FILE_ATTRIBUTE_NORMAL); 
}

BOOL CFileFindW::IsArchived()
{
	return MatchesMask(FILE_ATTRIBUTE_ARCHIVE); 
}

